//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------

#include "CEffect.h"
#include "CLevelEditor.h"
#include "CUserInterface.h"
#include "FpsCommonGLMaterialRenderer.h"
#include "FpsSceneManager.h"
#include "FpsMaterial.h"
#include "IXMLWriter.h"
#include "IFileSystem.h"
#include "IGUIEnvironment.h"
#include "IGUIWindow.h"
#include "IGUIListBox.h"
#include "lib2d\SpriteManager.h"
#include "lib2d\Sprite.h"
#include "IrrlichtDevice.h"

extern CGlobals* g;
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
int CLevelEditor::readEffectsPreset()
{
	//load effect sprite frame name list
	irr::core::stringc effectsFrameXML = "..\\..\\..\\src\\AutoGenerated\\EffectsFrame.xml";
	SGameList effectFrameList;
	if (LoadListFromFile(effectsFrameXML, effectFrameList))						
	{
		m_GameLists.push_back(effectFrameList);
	}

	for(int i=0; i<effectFrameList.Items.size(); ++i)
	{
		irr::core::stringc name(effectFrameList.Items[i].c_str());
		g->AddToFrameNameMap(name.c_str(), i);
	}

	//load effect sprite
	g->device->getFileSystem()->addFolderFileArchive((m_editorPath+"\\..\\..\\..\\data\\sprites\\_bin").c_str());
	g->device->getFileSystem()->addFolderFileArchive((m_editorPath+"\\..\\..\\..\\data\\sprites\\").c_str());
	CSpriteManager::instance()->LoadSprite("effects.bsprite");

	IXMLReader* xml = g->device->getFileSystem()->createXMLReader((m_editorPath+"\\effects.xml").c_str());

	if (!xml)
		return 1;
	
	while(xml->read())
	{
		if (core::stringw(L"effect") != xml->getNodeName())
		{
			continue;
		}

		io::IAttributes* attributes = NULL;

		core::stringw effectName = xml->getAttributeValue(L"name");
		CEffect* pEffect = new CEffect(effectName);
		m_Effects.push_back(pEffect);

		while(xml->read())
		{
			bool endreached = false;

			switch (xml->getNodeType())
			{
			case io::EXN_ELEMENT_END:
				if (core::stringw(L"effect") == xml->getNodeName())
				{
					endreached = true;
				}
				break;

			case io::EXN_ELEMENT:
				if (core::stringw(L"ps")==xml->getNodeName())
				{
					while(xml->read())
					{
						bool ps_endreached = false;
						switch (xml->getNodeType())
						{
							case io::EXN_ELEMENT_END:
								if (core::stringw(L"ps") == xml->getNodeName())
								{
									ps_endreached = true;
								}
								break;

							case io::EXN_ELEMENT:
								if (core::stringw(L"attributes")==xml->getNodeName())
								{
									// read attributes
									attributes = g->device->getFileSystem()->createEmptyAttributes();
									attributes->read(xml, true);

									//IFpsParticleSystemSceneNode* pNode = ((CFpsSceneManager*)g->sceneManager)->addFpsParticleSystemSceneNode();
									//pNode->grab();
									//pNode->deserializeAttributes(attributes);
									//pNode->setVisible(false);

									//stringc texName = attributes->getAttributeAsString("Texture");	
									bool useTexFile = false;//texName.size()>0 && texName.find("effects.tga")==-1;

									ITexture* pTexture = 0;
									if(useTexFile)
									{
										//pTexture = g->driver->getTexture(texName);
									}
									else
									{
										CSprite* spr = CSpriteManager::instance()->GetSprite("effects.bsprite");

										if(spr==0)
										{
											stringw strError = L"Can not open effects.bsprite";										
											g->guienv->addMessageBox(L"Error!", strError.c_str(), false);
										}
										else
										{
											pTexture = spr->GetTexture();										
											//pNode->setUVRect(spr->GetModuleUVRect(0,0));										
										}
									}

									//if (!pTexture && texName != "")
									//{
									//	stringw strError = L"Effect '";
									//	strError += effectName;
									//	strError += L"' cannot load texture '";
									//	strError += stringw(texName.c_str());
									//	strError += L"'!!!";
									//	g->guienv->addMessageBox(L"Error!", strError.c_str(), false);
									//}

									//pNode->setMaterialFlag(video::EMF_LIGHTING, false);
									//pNode->setMaterialTexture(0, pTexture);

									stringc strMatType = attributes->getAttributeAsString("MaterialType");
									for (int z = 0; z < g->device->getVideoDriver()->getMaterialRendererCount(); z ++)
									{
										if (strMatType == g->device->getVideoDriver()->getMaterialRendererName(z))
										{
											//pNode->setMaterialType((E_MATERIAL_TYPE)z);
											break;
										}
									}

									//pNode->setMaterialFlag(EMF_ZWRITE_ENABLE, false);
									//pNode->setMaterialFlag(EMF_FOG_ENABLE, false);

									//if(pNode->getMaterial(0).getMaterialType() == EMT_NONTRANSPARENT_ADDITIVE_REPLACE ||
									//	pNode->getMaterial(0).getMaterialType() == EMT_NONTRANSPARENT_ADDITIVE_MODULATE)
									//{
									//	pNode->getMaterial(0).setMaterialTypeParam(2, FPS_MATERIAL_RENDER_PRIORITY_ADDITIVE);
									//}

									irr::core::stringc frameName = attributes->getAttributeAsString("$SpriteFrameName");
									//pNode->setSpriteFrameName(frameName);

									if(!useTexFile)
									{
										int frameID = g->FindFrameIDByName(frameName.c_str());
										if(frameID<0)
											frameID=0;
										CSprite* spr = CSpriteManager::instance()->GetSprite("effects.bsprite");
									
										//pNode->setUVRect(spr->GetModuleUVRect(frameID,0));	
									}

									//m_Effects.getLast()->m_ParticleSystems.push_back(pNode);
								}
								break;
						}

						if (ps_endreached)
							break;
					}
				}
				break;

			default:
				break;
			}

			if (endreached)
				break;
		}
	}

	xml->drop();

	return 0;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::AddEffectToTypeList()
{
	for (u32 i=0; i < m_GameLists.size(); i++)
	{
		if (m_GameLists[i].Name == "EffectType")
		{
			for (u32 j=0; j < m_Effects.size(); j++)
			{
				m_GameLists[i].Items.push_back(m_Effects[j]->m_effectName);
			}
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::saveEffectPreset()
{
	IXMLWriter* xml = g->device->getFileSystem()->createXMLWriter((m_editorPath + "\\effects.xml").c_str());

	if (!xml)
		return;

	xml->writeXMLHeader();
	xml->writeLineBreak();

	for (u32 i = 0; i < m_Effects.size(); i++)
	{
		xml->writeElement(L"effect", false, L"name", m_Effects[i]->m_effectName.c_str());
		xml->writeLineBreak();

		for (u32 j = 0; j < m_Effects[i]->m_ParticleSystems.size(); j++)
		{
			xml->writeElement(L"ps");
			xml->writeLineBreak();

			IAttributes* pAttr = g->device->getFileSystem()->createEmptyAttributes();
			m_Effects[i]->m_ParticleSystems[j]->serializeAttributes(pAttr);
			
			SMaterial mat = m_Effects[i]->m_ParticleSystems[j]->getMaterial(0);
			//ITexture *pTexture = mat.getTexture(0);
			//if (pTexture)
			//{
			//	pAttr->addString( "Texture", g->getRelativePath(m_editorPath, pTexture->getName()).c_str() );
			//}
			//else
			//{
			//	pAttr->addString( "Texture", "" );
			//}

			irr::core::stringc frameName = m_Effects[i]->m_ParticleSystems[j]->getSpriteFrameName();
			pAttr->addString("$SpriteFrameName", frameName.c_str());

			//save frame id for game side use
			int frameID = g->FindFrameIDByName(frameName.c_str());
			pAttr->addInt("FrameID", frameID);

			pAttr->addString("MaterialType", g->device->getVideoDriver()->getMaterialRendererName(mat.MaterialType));
			
			pAttr->write(xml);
			xml->writeLineBreak();

			pAttr->drop();

			xml->writeClosingTag(L"ps");
			xml->writeLineBreak();
			xml->writeLineBreak();
		}

		xml->writeClosingTag(L"effect");
		xml->writeLineBreak();
		xml->writeLineBreak();
	}

	xml->drop();
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::SetObjectEffectType(ISceneNode* node, stringw effectType)
{
	//node->removeAll();

	list<ISceneNode*> Children = node->getChildren();
	list<ISceneNode*>::Iterator childIt = Children.begin();
	for(; childIt != Children.end(); childIt++)
	{
		g->sceneManager->addToDeletionQueue((*childIt));
	}

	int type = 0;
	bool bFound = false;

	for (u32 i=0; i < m_Effects.size(); i++)
	{
		if (m_Effects[i]->m_effectName == effectType)
		{
			type = i;
			bFound = true;
			break;
		}
	}

	if (!bFound)
	{
		stringw strError = L"Object ID ";
		strError += node->getID();
		strError += L" cannot load effect '";
		strError += effectType;
		strError += L"'!!!";
		g->guienv->addMessageBox(L"Error!", strError.c_str(), true);
		return;
	}

	for (u32 i = 0; i < m_Effects[type]->m_ParticleSystems.size(); i++)
	{
		ISceneNode* pNode = m_Effects[type]->m_ParticleSystems[i]->clone();
		pNode->setVisible(true);
		node->addChild(pNode);

		list<IFpsParticleAffector*> _affectors = ((IFpsParticleSystemSceneNode*)pNode)->getAffectors();
		core::list<IFpsParticleAffector*>::Iterator it = _affectors.begin();
		for(; it != _affectors.end(); it++)
		{
			if ((*it)->getType() == FPS_EPAT_ATTRACT)
			{
				vector3df newPoint = node->getAbsolutePosition() + ((IFpsParticleAttractionAffector*)(*it))->getPoint();
				((IFpsParticleAttractionAffector*)(*it))->setPoint(newPoint);
			}

			if ((*it)->getType() == FPS_EPAT_ROTATE)
			{
				vector3df newPoint = node->getAbsolutePosition() + ((IFpsParticleRotationAffector*)(*it))->getPivotPoint();
				((IFpsParticleRotationAffector*)(*it))->setPivotPoint(newPoint);
			}
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::createEffectNameInput(bool bClone)
{
	const dimension2d<u32> screen = g->driver->getScreenSize();

	IGUIWindow* pEffectNameInputWindow = g->guienv->addWindow(
		rect<s32>((screen.Width - 165) >> 1, (screen.Height >> 1) - 50, 
		((screen.Width - 165) >> 1) + 165, (screen.Height >> 1) + 50), 
		true, L"Enter effect name", 0, WND_ID_EFFECT_NAME);

	g->guienv->addEditBox(L"", rect<s32>(5, 45, 105, 65), true, pEffectNameInputWindow, EFFECT_NAME_ID_EDIT_NAME_BOX);
	g->guienv->addButton(rect<s32>(110, 45, 160, 65), pEffectNameInputWindow, bClone ? EFFECT_NAME_ID_OK_BTN_CLONE : EFFECT_NAME_ID_OK_BTN, L"OK");
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::createPSNameInput()
{
	const dimension2d<u32> screen = g->driver->getScreenSize();

	IGUIWindow* pPSNameInputWindow = g->guienv->addWindow(
		rect<s32>((screen.Width - 165) >> 1, (screen.Height >> 1) - 50, 
		((screen.Width - 165) >> 1) + 165, (screen.Height >> 1) + 50), 
		true, L"Enter particle system name", 0, WND_ID_PS_NAME);

	g->guienv->addEditBox(L"", rect<s32>(5, 45, 105, 65), true, pPSNameInputWindow, PS_NAME_ID_EDIT_NAME_BOX);
	g->guienv->addButton(rect<s32>(110, 45, 160, 65), pPSNameInputWindow, PS_NAME_ID_OK_BTN, L"OK");
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::SetEffectVisible(int effect, bool bVisible)
{
	for (u32 i=0; i < m_Effects.size(); i++)
	{
		m_Effects[i]->SetVisible(false);
	}

	if (bVisible && effect != -1)
	{
		m_Effects[effect]->SetVisible(bVisible);
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CLevelEditor::ReAddEffectsToScene()
{
	for (u32 i=0; i < m_Effects.size(); i++)
	{
		for (u32 j=0; j < m_Effects[i]->m_ParticleSystems.size(); j++)
		{
			g->sceneManager->getRootSceneNode()->addChild(m_Effects[i]->m_ParticleSystems[j]);
		}
	}
}
